use std::{
    collections::{BTreeMap, HashMap},
    sync::Arc,
};

use common::{
    base::{id_generator, status::Status}, service::sys_service_api::xport_service::ServiceInfos, utils::file_utils,
};

use tokio::sync::RwLock;

use crate::{application::Application, service::local_service::LocalService};

use semver::Version;

use super::dxc::DXC;


pub struct DXCManager {
    dxc_map: RwLock<HashMap<String, BTreeMap<Version, Arc<Box<DXC>>>>>,
}

#[allow(dead_code)]
impl DXCManager {
    pub fn new() -> DXCManager {
        DXCManager {
            dxc_map: RwLock::new(HashMap::new()),
        }
    }

    pub async fn add_dxc_and_return(&self, dxc_name: &str, version: &Version) -> Arc<Box<DXC>> {
        let airport: Arc<Box<super::airport::Airport>> = Application::get_airport();

        let mut dxc_map = self.dxc_map.write().await;

        let version_map = dxc_map
            .entry(String::from(dxc_name))
            .or_insert(BTreeMap::new());

        let dxc = version_map.get(version);

        if dxc.is_some() {
            return dxc.unwrap().clone();
        }
        let dxc = Arc::new(Box::new(DXC::new(airport, version.clone())));

        version_map.insert(version.clone(), dxc.clone());

        dxc.set_name(dxc_name.into()).await;

        dxc
    }

    /**
     *
     */
    pub async fn remove_dxc(&self, dxc_name: &str, version: &Version) {
        let mut dxc_map = self.dxc_map.write().await;
        let version_map = dxc_map.get_mut(dxc_name);
        if version_map.is_none() {
            return;
        }
        version_map.unwrap().remove(version);
    }

    pub async fn has_local_service_by_id(&self, service_id: i64) -> bool {
        let local_servcice = self.get_local_service_by_id(service_id).await;
        return local_servcice.is_some();
    }

    pub async fn get_local_service_by_id(&self, service_id: i64) -> Option<Arc<Box<LocalService>>> {
        let dxc_id = id_generator::get_dxc_id_by_service_id(service_id);
        let dxc = self.get_dxc_by_id(dxc_id).await;
        if dxc.is_none() {
            return None;
        }
        dxc.unwrap().get_local_service_by_id(service_id).await
    }

    /**
     *
     */
    pub async fn remove_dxc_channel_id(&self, channel_id: i64) {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                dxc.remove_all_remote_service_channel_id(channel_id).await;
            }
        }
    }

    pub async fn get_dxc_by_service_id(&self, service_id: i64) -> Option<Arc<Box<DXC>>> {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                let service = dxc.get_service_by_id(service_id).await;
                if service.is_some() {
                    return Some(dxc.clone());
                }
            }
        }
        None
    }
    /**
     *
     */
    pub async fn get_dxc_by_id(&self, service_id: i64) -> Option<Arc<Box<DXC>>> {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                if dxc.id() == service_id {
                    return Some(dxc.clone());
                }
            }
        }
        None
    }
    /**
     *
     */
    pub async fn get_dxc_by_name_and_version(
        &self,
        dxc_name: &str,
        version: &Version,
    ) -> Arc<Box<DXC>> {
        self.add_dxc_and_return(dxc_name, version).await
    }

    /**
     *
     */
    pub async fn get_dxc_by_name_and_version_without_build(
        &self,
        dxc_name: &str,
        version: &Version,
    ) -> Option<Arc<Box<DXC>>> {
        let dxc_map = self.dxc_map.read().await;
        let version_map = dxc_map.get(dxc_name);
        if version_map.is_none() {
            return None;
        }
        let dxc = version_map.unwrap().get(version);
        if dxc.is_some() {
            return Some(dxc.unwrap().clone());
        }
        None
    }

    /**
     *
     */
    pub async fn ack_normal_message(&self, _conn_id: i64, ack_msg_id_list: &Vec<i64>) {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for msg_id in ack_msg_id_list.iter() {
                for (_, dxc) in version_map.iter() {
                    if dxc.ack_message(*msg_id).await {
                        break;
                    }
                }
            }
        }
    }

    pub async fn load_local_dxc(
        &self,
        dxc_name: &str,
        dxc_version: &Version,
        service_name: &str,
        config: &str,
    ) -> Result<(), Status> {
        //
        let dxc_str_version = dxc_version.to_string().replace(".", "_");
        let dxc_path = format!("./dxc/{}_{}.dxc", dxc_name, &dxc_str_version);
        let is_dxc_exist = file_utils::is_file_exist(&dxc_path).await;
        if !is_dxc_exist {
            return Err(Status::error(format!("DXC:{} 不存在!", dxc_path)));
        }
        let dxc = self.add_dxc_and_return(dxc_name, &dxc_version).await;
        if dxc.has_local_service_by_name(service_name).await {
            return Err(Status::error(format!(
                "加载 dxc:{} version:{:?} service:{}， 服务已经存在",
                dxc_name, dxc_name, service_name
            )));
        }
        dxc.load_local_service(service_name, config).await
    }

    pub async fn get_dxc_id_by_name_and_version(
        &self,
        dxc_name: &str,
        version: &Version,
    ) -> Option<i64> {
        let dxc = self
            .get_dxc_by_name_and_version_without_build(dxc_name, version)
            .await;
        return if let Some(dxc) = dxc {
            Some(dxc.id())
        } else {
            None
        };
    }

    pub async fn get_all_local_service_info(&self, filter_system: bool) -> ServiceInfos {
        let mut local_service_infos = ServiceInfos::default();
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                local_service_infos
                    .services
                    .append(&mut dxc.get_all_local_service_info(filter_system).await.services);
            }
        }
        local_service_infos
    }

    /**
     *
     */
    pub async fn add_channel_id_to_remote_dxc(&self, conn_id: i64, channel_id: i64) {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                dxc.add_channel_to_remote_service_by_conn_id(conn_id, channel_id)
                    .await;
            }
        }
    }

    /**
     *
     */
    pub async fn remove_channel_id_in_remote_dxc(&self, conn_id: i64, channel_id: i64) {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                dxc.remove_channel_in_remote_service_by_conn_id(conn_id, channel_id)
                    .await;
            }
        }
    }

    /**
     *
     */

    pub async fn send_message_to_one_remote_dxc(&self, conn_id: i64, message: &Vec<u8>) {
        let dxc_map = self.dxc_map.read().await;
        for (_, version_map) in dxc_map.iter() {
            for (_, dxc) in version_map.iter() {
                let remote_service = dxc.get_remote_service_by_conn_id(conn_id).await;
                if remote_service.is_none() {
                    continue;
                }
                let remote_service = remote_service.unwrap();
                remote_service.message_in(message);
                break;
            }
        }
    }
}
